package cn.edu.sjtu;

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import cn.edu.sjtu.dfa.Call;
import cn.edu.sjtu.dfa.CallWithReturn;
import cn.edu.sjtu.dfa.Instruction;

public class OverallCFGBuilder {
	
	private HashMap<String, HashMap<String,List<Instruction>>> cfgMap;
	private HashMap<String, List<Instruction>> m;
	private ArrayList<String> al;
	
	public OverallCFGBuilder() {
		this.cfgMap = DataFlowAnalyzer.ils;
		m = new HashMap<String, List<Instruction>>();
		al = new ArrayList<String>();
	}
	
	public int getMethodNumber(){
		int size = 0;
		HashMap<String, List<Instruction>> tm = null;
		Iterator i = cfgMap.entrySet().iterator();
		while (i.hasNext()) {
			Map.Entry e1 = (Map.Entry)i.next();
			tm = (HashMap<String, List<Instruction>>)e1.getValue();
			Iterator j = tm.entrySet().iterator();
			while (j.hasNext()) {
				Map.Entry e2 = (Map.Entry)j.next();
				size++;
			}
		}
		return size;
	}
	
	public void getInvokedMethodName(){
		HashMap<String, List<Instruction>> tm = null;
		Iterator i = cfgMap.entrySet().iterator();
		while (i.hasNext()) {
			Map.Entry e1 = (Map.Entry)i.next();
			tm = (HashMap<String, List<Instruction>>)e1.getValue();
			Iterator j = tm.entrySet().iterator();
			while (j.hasNext()) {
				Map.Entry e2 = (Map.Entry)j.next();
				List<Instruction> l = (List<Instruction>)e2.getValue();
				for (int x = 0; x < l.size(); x++) {
					if (l.get(x).getClass().equals(Call.class) || l.get(x).getClass().equals(CallWithReturn.class)) {
						if (l.get(x).getClass().equals(Call.class)){
							if (!((Call)l.get(x)).getFunction().startsWith("android") && !((Call)l.get(x)).getFunction().startsWith("java"))
								System.out.println("a" + ((Call)l.get(x)).getFunction());
						}
						else {
							if (!((CallWithReturn)l.get(x)).getFunctionCall().getFunction().startsWith("android") && !((CallWithReturn)l.get(x)).getFunctionCall().getFunction().startsWith("java"))
								System.out.println("b" + ((CallWithReturn)l.get(x)).getFunctionCall().getFunction());
						}
					}
				}
			}
		}
	}
	
	public void outputOverallCFG(){
		String[] t;
		String className;
		String methodName;
		int count = 0;
		try {
			PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter("graph\\CFG.dot")));
			out.println("digraph G {");
			//first step
			HashMap<String, List<Instruction>> tm = null;
			Iterator i = cfgMap.entrySet().iterator();
			while (i.hasNext()) {
				Map.Entry e1 = (Map.Entry)i.next();
				t = ((String)e1.getKey()).split("\\.");
				className = t[t.length - 1];
				tm = (HashMap<String, List<Instruction>>)e1.getValue();
				Iterator j = tm.entrySet().iterator();
				while (j.hasNext()) {
					Map.Entry e2 = (Map.Entry)j.next();
					methodName = (String)e2.getKey();
					t = methodName.split(" ");
					methodName = t[t.length - 1].substring(0, t[t.length - 1].lastIndexOf(")") + 1);
					m.put(className + "." + methodName, (List<Instruction>)e2.getValue());
					al.add(className + "." + methodName);
					out.println("\t" + count + "[label=\"" + className + "." + methodName + "\"];");
					count++;
				}
			}
			//second step
			for (int w = 0; w < al.size(); w++) {
				List<Instruction> l = m.get(al.get(w));
				for (int x = 0; x < l.size(); x++) {
					if (l.get(x).getClass().equals(Call.class) || l.get(x).getClass().equals(CallWithReturn.class)) {
						if (l.get(x).getClass().equals(Call.class)){
							if (!((Call)l.get(x)).getFunction().startsWith("android") && !((Call)l.get(x)).getFunction().startsWith("java")) {
								String[] s = ((Call)l.get(x)).getFunction().split("\\.");
								for (int y = 0; y < al.size(); y++){
									if (al.get(y).contains(s[s.length - 2] + "." + s[s.length - 1])){
										out.println(w + " -> " + y + ";");
									}
								}
							}
						}
						else {
							if (!((CallWithReturn)l.get(x)).getFunctionCall().getFunction().startsWith("android") && !((CallWithReturn)l.get(x)).getFunctionCall().getFunction().startsWith("java")) {
								String temp = ((CallWithReturn)l.get(x)).getFunctionCall().getFunction();
								String[] s = temp.split("\\.");
								for (int y = 0; y < al.size(); y++){
									if (al.get(y).contains(s[s.length - 2] + "." + s[s.length - 1])){
										out.println(w + " -> " + y + ";");
									}
								}
							}
						}
					}
				}
			}
			out.println("}");
			out.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}
